package com.oe.market.modules.ele.service;

import cn.hutool.http.HttpUtil;
import com.google.gson.Gson;
import com.oe.market.modules.base.ex.BusinessException;
import com.oe.market.modules.base.model.bean.Account;
import com.oe.market.modules.base.service.AccountService;
import com.oe.market.modules.ele.model.bean.Cookie;
import com.oe.market.modules.ele.model.bean.CookieUseCount;
import com.oe.market.modules.ele.model.bean.RedPackage;
import com.oe.market.modules.ele.model.dao.AccountDao;
import com.oe.market.modules.ele.model.dao.CookieUseCountDao;
import com.oe.market.modules.ele.model.dao.RedPackageDao;
import com.oe.market.modules.ele.model.dao.CookieDao;
import com.oe.market.modules.ele.model.dto.EleRedPackageDto;
import com.oe.market.modules.ele.model.dto.RedPackageResponseDto;
import com.oe.market.modules.ele.model.mapper.EleRedPackageMapper;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class EleRedPackageService {
    private static final Logger log = LoggerFactory.getLogger(EleRedPackageService.class);

    public String add(EleRedPackageDto eleRedPackageDto, Account account) throws BusinessException {

        EleRedPackageMapper eleRedPackageMapper = new EleRedPackageMapper(eleRedPackageDto, account);
        if (0 != RedPackageDao.me.findByGroupSn(eleRedPackageDto.groupSn).size()) {
            return "红包已经存在";
        }

        String result = RedPackageDao.me.append(eleRedPackageMapper.getRedPackage());
        if (result != null) {
            throw new BusinessException("添加红包失败");
        }
        return result;
    }

    public static String take(String url) throws BusinessException {
        List<Cookie> cookies = CookieDao.me.searchUse();
        Account account = AccountService.check("robot","2023fadf4085d6dba4433301521da8be0c69dac2df74599ccb9b1d8d9967a693");
        EleRedPackageDto eleRedPackageDto = EleRedPackageService.urlDecode(url);
        EleRedPackageService eleRedPackageService = new EleRedPackageService();
        return eleRedPackageService.take(eleRedPackageDto, account, cookies);
    }

    public String take(EleRedPackageDto eleRedPackageDto, Account account, List<Cookie> cookies) throws BusinessException {
        // 开始抢红包
        int userInfoPos = 0;
        int currentPos = 0;
        List<String> snsHashList = new ArrayList<>();
        String ret = null;
        for (int lastCureentPos = 0; userInfoPos < cookies.size() && userInfoPos < 20; ++userInfoPos) {
            try {
                Cookie cookie = cookies.get(userInfoPos);
                // 抢红包
                RedPackageResponseDto redPackageResponseDto = takeRedPackage(eleRedPackageDto.groupSn, cookie);
                snsHashList.add(cookie.getSnsHash());
                // 发生未知错误
                if ((redPackageResponseDto.getName() != null
                && redPackageResponseDto.getName().equals("TOO_BUSY"))) {
                    TimeUnit.SECONDS.sleep(1);
                }
                else if (redPackageResponseDto.getName() != null
                        && redPackageResponseDto.getName().equals("PHONE_IS_EMPTY")){
                    CookieUseCountDao.me.ban(cookie.getCookieId());
                }
                else if (null == redPackageResponseDto) {
                    String error = "未知错误，已经执行" + userInfoPos + "次。"
                            + "幸运位: " + eleRedPackageDto.luckyPos + ",当前位:" + currentPos
                            + "再抢" + (eleRedPackageDto.luckyPos - currentPos) + "次即可获得最大红包["
                            + (redPackageResponseDto.getName() != null ? redPackageResponseDto.getName():"")
                            + "]";
                    throw new BusinessException(error);
                }
                else if (null == redPackageResponseDto.getName()) {
                    if (currentPos != redPackageResponseDto.getPromotionRecords().size()) {
                        currentPos = redPackageResponseDto.getPromotionRecords().size();
                        CookieUseCountDao.me.useOnce(cookie.snsHash);
                    }
                    ret = null;
                    if (currentPos >= (eleRedPackageDto.luckyPos - 1)) {
                        break;
                    }
                    // 满足最大红包条件
                    TimeUnit.SECONDS.sleep(3);
                }

            } catch (BusinessException e) {
                if (null == ret || ret.isEmpty()) {
                    ret = e.getMessage();
                }
                else throw e;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (ret != null) {
            throw new BusinessException(ret);
        }

        // 添加红包记录
        try {
            EleRedPackageMapper eleRedPackageMapper = new EleRedPackageMapper(eleRedPackageDto, account);
            RedPackage redPackage = eleRedPackageMapper.getRedPackage();
            redPackage.currentPos = currentPos;
            if (snsHashList.size() > 2) {
                snsHashList = snsHashList.subList(0,2);
            }
            redPackage.robotIdList = new Gson().toJson(snsHashList);

            RedPackageDao.me.append(redPackage);
            RedPackageDao.me.updateCurrentAndRobotList(redPackage.groupSn,
                    currentPos, redPackage.robotIdList);
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        // 扣除可领取次数
        if (userInfoPos > 0) {
            try {
                String result = AccountDao.me.useOnce(account.getAccountId());
                if (null != result) {
                    log.error(result + "内部错误！消耗次数失败:" + account.getAccountId());
                }
            } catch (SQLException e) {
                // @bug 若出现此类错误，应该加以控制
                //      处理方式暂且搁置
                log.error(e.getMessage());
                log.error("内部错误！消耗次数失败:" + account.getAccountId());
                log.error("request: " + new Gson().toJson(eleRedPackageDto));
            }
        }

        return ret;
    }


    public RedPackage getUselessRedPackage() {
        List<RedPackage> redPackages = RedPackageDao.me.searchUseless();
        for (RedPackage redPackage : redPackages) {
            if (redPackage.currentPos > 14) {
                RedPackageDao.me.ban(redPackage.groupSn);
            }
            return redPackage;
        }
        return null;
    }


    public RedPackage getUsefulRedPackage() {
        List<RedPackage> redPackages = RedPackageDao.me.searchUseful();
        Gson gson = new Gson();
        for (RedPackage redPackage : redPackages) {
            List<String> robots = gson.fromJson(redPackage.robotIdList, List.class);
            if (robots.size() != 0) {
                for (String robot : robots) {
                    // 获取一个机器人
                    List<CookieUseCount> cookieUseCounts = CookieUseCountDao.me.findBySnsHash(robot);
                    if (cookieUseCounts.size() == 0) {
                        continue;
                    }
                    List<Cookie> cookies = CookieDao.me.findByCookieId(cookieUseCounts.get(0).getInfoId());
                    if (0 == cookies.size()) {
                        continue;
                    }
                    Cookie cookie = cookies.get(0);
                    try {
                        redPackage = checkRedPackageCurrentPos(redPackage, cookie);

                        // 检验红包合法
                        if (null != redPackage
                                && redPackage.currentPos < redPackage.luckyPos
                                && redPackage.currentPos < 10) {
                            return redPackage;
                        }
                    } catch (BusinessException e) {
                        e.printStackTrace();
                    }
                }

                List<Cookie> cookies = CookieDao.me.searchUse();
                if (cookies.size() == 0 || redPackage == null) {
                    continue;
                }
                try {
                    redPackage = checkRedPackageCurrentPos(redPackage, cookies.get(0));

                    if (null != redPackage && redPackage.currentPos < redPackage.luckyPos) {
                        return redPackage;
                    }
                } catch (BusinessException ignored) {
                }
            }


        }

        return null;
    }

    public static RedPackage checkRedPackageCurrentPos(RedPackage redPackage, Cookie cookie) throws BusinessException {
        // 查询当前位置
        EleRedPackageService eleRedPackageService = new EleRedPackageService();
        RedPackageResponseDto redPackageResponseDto = eleRedPackageService.takeRedPackage(redPackage.groupSn, cookie);
        if ((redPackageResponseDto.getName() != null
                && redPackageResponseDto.getName().equals("TOO_BUSY"))) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        else if (redPackageResponseDto.getName() != null
                && redPackageResponseDto.getName().equals("PHONE_IS_EMPTY")){
            CookieUseCountDao.me.banInfoId(cookie.getCookieId());
        }
        if (null == redPackageResponseDto.getName()) {
            Integer currentPos = redPackageResponseDto.getPromotionRecords().size();

            // 更新最新位置
            if (!currentPos.equals(redPackage.currentPos)) {
                RedPackageDao.me.updateCurrent(redPackage.groupSn, currentPos);
                redPackage.currentPos = currentPos;
            }
            return redPackage;
        }
        return null;

    }


    // 抢红包,成功返回当前已抢红包数量，失败返回负值
    public RedPackageResponseDto takeRedPackage(String groupSn, Cookie cookie) throws BusinessException {
        try {
            // 转换信息
            Gson gson = new Gson();
            EleRedPackageDto body = gson.fromJson(cookie.body, EleRedPackageDto.class);
            body.groupSn = groupSn;

            // 设置请求的接口
            String visitUrl = "https://h5.ele.me/restapi/marketing/promotion/weixin/" + body.openid;

            // 发起请求
            String lastResponse = sendPost(visitUrl, gson.toJson(body), cookie.cookie);
            // 分析结果
            return gson.fromJson(lastResponse,RedPackageResponseDto.class);
        }
        catch (IOException e) {
            log.error(e.getMessage());
            log.error("request: " + groupSn);
            log.error("request: " + new Gson().toJson(cookie));
            return null;
        }
    }

    public static EleRedPackageDto urlDecode(String url) {
        EleRedPackageDto eleRedPackageDto = new EleRedPackageDto();
        if (null != url) {
            try {
                String replace = url.replace("#", "?");
                Map map = EleRedPackageService.URLRequest(replace);
                // https://h5.ele.me/hongbao/#hardware_id=&is_lucky_group=True&lucky_number=0&track_id=&platform=0&sn=2a0df4a18eafe03a&theme_id=3169&device_id=&refer_user_id=14544676
                eleRedPackageDto.groupSn = map.get("sn").toString();
                if (null == eleRedPackageDto.luckyPos || eleRedPackageDto.luckyPos == 0) {
                    eleRedPackageDto.luckyPos = Integer.valueOf(map.get("lucky_number").toString());
                    if (eleRedPackageDto.luckyPos == 0) {
                        eleRedPackageDto.luckyPos = EleRedPackageService.getLuckNumber(eleRedPackageDto.groupSn);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        return eleRedPackageDto;
    }

    public static Map<String, String> URLRequest(String info) throws MalformedURLException {
        Map<String, String> mapRequest = new HashMap<String, String>();

        String[] arrSplit=null;

        URL url = new URL(info);
        String strUrlParam = url.getQuery();
        if(strUrlParam==null)
        {
            return mapRequest;
        }
        //每个键值为一组 www.2cto.com
        arrSplit=strUrlParam.split("[&]");
        for(String strSplit : arrSplit)
        {
            String[] arrSplitEqual=null;
            arrSplitEqual= strSplit.split("[=]");

            //解析出键值
            if(arrSplitEqual.length > 1)
            {
                //正确解析
                mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);

            }
            else
            {
                if(!arrSplitEqual[0].equals(""))
                {
                    //只有参数没有值，不加入
                    mapRequest.put(arrSplitEqual[0], "");
                }
            }
        }
        return mapRequest;
    }

    public static Integer getLuckNumber(String groupSn){
        if (null == groupSn || groupSn.isEmpty())
            return 0;
        String respond = HttpUtil.get("https://h5.ele.me/restapi/marketing/themes/0/group_sns/" + groupSn);
        EleRedPackageDto temp = new Gson().fromJson(respond, EleRedPackageDto.class);
        return temp.luckNumber;
    }


    private static String sendPost(String url, String body, String cookie) throws BusinessException, IOException {
        OkHttpClient okHttpClient = new OkHttpClient(); // 创建OkHttpClient对象

        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), body);
        Request request = new Request.Builder()
                .header("Content-Type", "application/json")
                .header("Host", "h5.ele.me")
                .header("Origin", "https://h5.ele.me")
                .header("Accept", "*/*")
                .header("connection", "Keep-Alive")
                .header("cookie", cookie)
                .header("user-agent",
                        "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat QBCore/3.43.901.400 QQBrowser/9.0.2524.400")
                .url(url)
                .post(requestBody)
                .build();

        Response response = okHttpClient.newCall(request).execute();

        if (!response.isSuccessful()) {
//            return response.body().string();
            log.warn("request ele service response 400 " + body);
//            throw new IOException("Unexpected code " + response);
        }

        return response.body().string();

    }

    private static String sendPost1(String url, String body, String cookie) throws BusinessException, IOException {
        PrintWriter out = null;
        BufferedReader in = null;
        String result = "";
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            URLConnection conn = realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setRequestProperty("Host", "h5.ele.me");
            conn.setRequestProperty("Origin", "https://h5.ele.me");
            conn.setRequestProperty("Accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("cookie", cookie);
            conn.setRequestProperty("user-agent",
                    "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36 MicroMessenger/6.5.2.501 NetType/WIFI WindowsWechat QBCore/3.43.901.400 QQBrowser/9.0.2524.400");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            out = new PrintWriter(conn.getOutputStream());
            // 发送请求参数
            out.print(body);
            // flush输出流的缓冲
            out.flush();
            // 定义BufferedReader输入流来读取URL的响应
            in = new BufferedReader(
                    new InputStreamReader(conn.getInputStream()));

            String line;
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            throw new BusinessException("网络请求失败");
        }
        //使用finally块来关闭输出流、输入流
        finally{
            try{
                if(out!=null){
                    out.close();
                }
                if(in!=null){
                    in.close();
                }
            }
            catch(IOException e){
                throw e;
            }
        }
        return result;
    }

    public static void main(String[] args) {
        try {
            String ret = EleRedPackageService.take("https://h5.ele.me/hongbao/#hardware_id=&is_lucky_group=True&lucky_number=10&track_id=&platform=4&sn=2a08a6b8732e78a0&theme_id=3041&device_id=&refer_user_id=10959777");
            System.out.println(ret);
        } catch (BusinessException e) {
            e.printStackTrace();
        }
        System.out.println("end");
    }

}
